package org.jside.xtools.encoding;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import org.xidea.commons.i18n.CharsetDetect;
import org.xidea.commons.i18n.CharsetSelector;
import org.xidea.commons.i18n.DefaultCharsetSelector;

public class EncodingTransformer extends JFrame {

	private JFileChooser fileChooser = new JFileChooser();
	{
		fileChooser.setDialogTitle("选择目录");
		fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		fileChooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
			@Override
			public boolean accept(File f) {
				return f.isDirectory();
			}

			@Override
			public String getDescription() {
				return "目录";
			}

		});
	}

	private JTextField sourceInput = new JTextField();
	// "C:\\Documents and
	// Settings\\Administrator\\桌面\\JSISide\\JSISide\\web\\decorator");
	private JButton sourceButton = new JButton("选择源文件目录");
	private JTextField destInput = new JTextField();
	// "C:\\Documents and
	// Settings\\Administrator\\桌面\\JSISide\\JSISide\\web\\decorator2");
	private JButton destButton = new JButton("选择源文件目录");
	private JButton beginButton = new JButton("开始转换");

	private JRadioButton askIfNeed = new JRadioButton("询问");// 当存在多个编码可能的时候是否询问（若否，则自动按默认编码执行）");

	private JTextArea output = new JTextArea();

	private JComboBox sourceEncoding = new JComboBox(new String[] { "UTF-8",
			"GBK" });
	private JComboBox destEncoding = new JComboBox(new String[] { "UTF-8",
			"GBK" });

	public EncodingTransformer() {
		initialize();
		sourceButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				fileChooser.setSelectedFile(new File(sourceInput.getText()));
				int status = fileChooser
						.showOpenDialog(EncodingTransformer.this);
				if (status == JFileChooser.APPROVE_OPTION) {
					File file = fileChooser.getSelectedFile();
					try {
						sourceInput.setText(file.getCanonicalPath());
					} catch (IOException e1) {
						output.append("ERROR:" + e1.getMessage());
					}
				}
			}
		});
		destButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				fileChooser.setSelectedFile(new File(destInput.getText()));
				int status = fileChooser
						.showOpenDialog(EncodingTransformer.this);
				if (status == JFileChooser.APPROVE_OPTION) {
					File file = fileChooser.getSelectedFile();
					try {
						destInput.setText(file.getCanonicalPath());
					} catch (IOException e1) {
						output.append("ERROR:" + e1.getMessage());
					}
				}
			}
		});
		beginButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				File sourceFile = new File(sourceInput.getText());
				String dest = destInput.getText();
				if (sourceFile.exists() && dest.length() > 0) {
					File destFile = new File(dest);
					if (destFile.exists()) {
						int status = JOptionPane.showConfirmDialog(
								EncodingTransformer.this, "目标目录已经存在:"
										+ destFile + "\r\b继续操作将覆盖目标目录");
						if (status != JOptionPane.OK_OPTION) {
							return;
						}
					}
					walk(sourceFile, destFile);

				} else {
					JOptionPane.showConfirmDialog(EncodingTransformer.this,
							"请选择源文件目录和目标文件目录");
				}
			}
		});
	}

	public void info(String msg) {
		this.output.append(msg + "\r\n");
	}

	private void initialize() {
		this.setTitle("批量编码工具");
		this.setSize(new Dimension(600, 500));
		this.setPreferredSize(new Dimension(600, 500));

		GridBagLayout layout = new GridBagLayout();
		this.setLayout(layout);

		GridBagConstraints c = new GridBagConstraints();
		c.fill = GridBagConstraints.BOTH;
		c.insets = new Insets(4, 4, 4, 4);

		c.weightx = 6.0;
		c.gridwidth = 1;
		c.gridx = GridBagConstraints.RELATIVE;
		this.add(sourceInput, c);

		c.weightx = 1.0;
		c.gridwidth = GridBagConstraints.REMAINDER;
		this.add(sourceButton, c);

		c.weightx = 6.0;
		c.gridwidth = 1;
		this.add(destInput, c);

		c.weightx = 1.0;
		c.gridwidth = GridBagConstraints.REMAINDER;
		this.add(destButton, c);

		c.weightx = 1.0;
		c.gridwidth = 1;
		JPanel encodingPanel = new JPanel();
		encodingPanel.add(new JLabel("原始编码"));
		encodingPanel.add(sourceEncoding);
		encodingPanel.add(new JLabel("->目标编码"));
		encodingPanel.add(destEncoding);

		this.add(encodingPanel, c);
		c.gridwidth = GridBagConstraints.REMAINDER;
		this.add(beginButton, c);

		c.weightx = 1.0;
		c.fill = GridBagConstraints.BOTH;
		c.weighty = 100;
		c.anchor = GridBagConstraints.CENTER;
		c.gridwidth = GridBagConstraints.REMAINDER;
		output.setBorder(BorderFactory.createEtchedBorder());
		this.add(new JScrollPane(output), c);

		c.fill = GridBagConstraints.NONE;
		c.weighty = 1;
		c.anchor = GridBagConstraints.CENTER;
		c.gridwidth = GridBagConstraints.REMAINDER;

	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		EncodingTransformer marker = new EncodingTransformer();
		marker.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		marker.setVisible(true);
	}

	private Collection<String> waterExtMap = new HashSet<String>(Arrays
			.asList("java,js".split("[,]")));

	protected void walk(final File source, final File dest) {
		if (!dest.exists()) {
			dest.mkdirs();
		}
		File[] dirs = source.listFiles(new java.io.FileFilter() {
			public boolean accept(File file) {
				if (file.isDirectory()) {
					walk(file, new File(dest, file.getName()));
				} else {
					try {
						String name = file.getName();
						String ext = name.substring(name.lastIndexOf('.') + 1)
								.toLowerCase();
						if (waterExtMap.contains(ext)) {
							transform(file, new File(dest, name));
						} else {
							copy(file, new File(dest, name));
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				return false;
			}
		});
	}

	protected void copy(File source, File dest) throws IOException {
		if (!source.equals(dest)) {
			dest.createNewFile();
			FileInputStream in = new FileInputStream(source);
			FileOutputStream out = new FileOutputStream(dest);

			byte[] cbuf = new byte[1024];
			int count;
			while ((count = in.read(cbuf)) >= 0) {
				out.write(cbuf, 0, count);
			}
			out.flush();
			out.close();
		}
	}

	protected void transform(final File source, File dest) throws IOException {
		DefaultCharsetSelector charserSelector = new DefaultCharsetSelector(
				String.valueOf(this.sourceEncoding.getSelectedItem())) {
			public String selectCharset(String[] options) {
				info("WARNING:文件<" + source + ">存在多种编码可能。");
				if (defaultCharset != null) {
					for (int i = 0; i < options.length; i++) {
						if (defaultCharset.equalsIgnoreCase(options[i])) {
							info("采用默认编码处理：" + defaultCharset);
							return latestSelectedCharset = defaultCharset;
						}
					}
				}
				info("没有找到匹配的默认编码，选取第一个可能的字符集：" + options[0]);
				return latestSelectedCharset = options[0];
			}
		};
		// TODO:ask
		InputStream in = new FileInputStream(source);
		String result = CharsetDetect.getText(in, Locale.CHINESE,
				charserSelector);
		in.close();
		charserSelector.getLatestSelectedCharset();
		if (!dest.exists()) {
			dest.createNewFile();
		}
		Writer out = new OutputStreamWriter(new FileOutputStream(dest), String
				.valueOf(this.destEncoding.getSelectedItem()));
		out.write(result);
		info("INFO:文件“" + dest + "”  转换成功");
		out.flush();
		out.close();

	}
}
